﻿// Copyright (c) Inossem. All rights reserved.
// Licensed under the LGPL-3.0 license. See LICENSE file in the project root for full license information.
using DWF.Common.Activities.Contract;
using DWF.Studio.RemoteCtrls.Services;
using DWF.Studio.RemoteCtrls.ActivityToolBox.Node;
using DWF.Studio.RemoteCtrls.ActivityToolBox.Repository;
using System;
using System.Activities;
using System.Activities.Presentation;
using System.Activities.Presentation.Model;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Linq;
using System.Reflection;
using System.Resources;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace DWF.Studio.RemoteCtrls.ActivityToolBox
{
    /// <summary>
    /// ActivitiesToolBox.xaml 的交互逻辑
    /// </summary>
    public partial class UCtrlActivityToolBox : UserControl
    {
        private SortableObservableCollection<TreeNode> _nodeCollection = new SortableObservableCollection<TreeNode>();

        private List<ActivityNode> _activityNodeCache = null;

        /// <summary>
        /// 收藏
        /// </summary>
        private FavoriteCategory _favoriteCategory = null;
        /// <summary>
        /// 最近
        /// </summary>
        private RecentCategory _recentCategory = null;

        private ActivityNode _dragDropActivity = null;

        private int _favoriteMaxCount = 20;

        private int _recentMaxCount = 10;

        public UCtrlActivityToolBox()
        {
            InitializeComponent();
            init();
        }

        private void init()
        {
            this.tvActivities.ItemsSource = _nodeCollection;
            this._activityNodeCache = new List<ActivityNode>();

            _favoriteCategory = new FavoriteCategory() { DisplayName = LocalizationProvider.GetLocalizedString("UCtrlActivitiesToolBox_Category_DisplayName_Favorites"), SortNo = int.MinValue, IsExpanded = true };
            _recentCategory = new RecentCategory() { DisplayName = LocalizationProvider.GetLocalizedString("UCtrlActivitiesToolBox_Category_DisplayName_Recent"), SortNo = int.MinValue + 1, IsExpanded = true };
            btnExpand.ToolTip = LocalizationProvider.GetLocalizedString("UCtrlProjectExplorer_Top_Button_AllExpand");
            btnCollapse.ToolTip = LocalizationProvider.GetLocalizedString("UCtrlProjectExplorer_Top_Button_AllCollapse");
        }
        /// <summary>
        /// 暴露给代理
        /// </summary>
        /// <param name="activityTypes"></param>
        /// <param name="activityLoading"></param>
        internal void LoadActivies(IEnumerable<Type> activityTypes, Action<string> activityLoading)
        {
            loadActivies(activityTypes, _activityNodeCache, activityLoading);
        }
        /// <summary>
        /// 加载全部内容
        /// </summary>
        /// <param name="activityTypes"></param>
        /// <param name="activityNodes"></param>
        /// <param name="activityLoading"></param>
        private void loadActivies(IEnumerable<Type> activityTypes, List<ActivityNode> activityNodes = null, Action<string> activityLoading = null)
        {
            List<Tuple<Type, List<ToolBoxCategoryAttribute>>> activityTuples = new List<Tuple<Type, List<ToolBoxCategoryAttribute>>>();
            foreach (var activityType in activityTypes)
            {
                var categoryAttributes = activityType.GetCustomAttributes<ToolBoxCategoryAttribute>(false)?.OrderBy(item => item.LevelSort).ToList();
                if (categoryAttributes != null && categoryAttributes.Count() > 0)
                {
                    var tuple = new Tuple<Type, List<ToolBoxCategoryAttribute>>(activityType, categoryAttributes);
                    activityTuples.Add(tuple);
                }
                else
                {
                    var assembly = activityType.Assembly;
                    var resourceNames = assembly.GetManifestResourceNames();
                    var assemblyName = assembly.GetName();
                    var resourceName = assemblyName.Name + ".Resources.viewlangdic";

                    short sortNum = Int16.MaxValue;
                    string displayName = assemblyName.Name;

                    var isExisting = resourceNames.Any(item => item.Contains(resourceName));
                    if (isExisting)
                    {
                        var resourceManager = new ResourceManager(resourceName, assembly);

                        var DISPLAY_NO_string_value = resourceManager.GetString("DISPLAY_NO", System.Threading.Thread.CurrentThread.CurrentCulture);
                        short DISPLAY_NO_int_value;
                        var isok = Int16.TryParse(DISPLAY_NO_string_value, out DISPLAY_NO_int_value);
                        if (isok)
                        {
                            sortNum = DISPLAY_NO_int_value;
                        }

                        var GROUP_NAME_string_value = resourceManager.GetString("GROUP_NAME", System.Threading.Thread.CurrentThread.CurrentCulture);
                        if (!String.IsNullOrWhiteSpace(GROUP_NAME_string_value))
                        {
                            displayName = GROUP_NAME_string_value;
                        }
                    }

                    Tuple<Type, List<ToolBoxCategoryAttribute>> tuple = new Tuple<Type, List<ToolBoxCategoryAttribute>>(activityType, new List<ToolBoxCategoryAttribute>() { new ToolBoxCategoryAttribute(displayName, 0, sortNum) });
                    activityTuples.Add(tuple);
                }
            }

            _nodeCollection.Clear();
            foreach (var activityTuple in activityTuples)
            {
                var activityNode = buildNodesRecursion(activityTuple, 0, null, _nodeCollection);
                if (activityNode != null)
                {
                    activityLoading?.Invoke(activityNode.DisplayName);
                    activityNodes?.Add(activityNode);
                }
            }

            buildFavoriteNodes(_favoriteCategory);
            buildRecentNodes(_recentCategory);

            _nodeCollection.Add(_favoriteCategory);
            _nodeCollection.Add(_recentCategory);

            var items = _nodeCollection.OrderBy(item => item.IsLeaf).ThenBy(item => item.SortNo);
            _nodeCollection.Sort(items);
        }
        
        /// <summary>
        /// 加载活动递归
        /// </summary>
        /// <param name="activityTuple"></param>
        /// <param name="index"></param>
        /// <param name="parentNode"></param>
        /// <param name="currentNodes"></param>
        /// <returns></returns>
        private ActivityNode buildNodesRecursion(Tuple<Type, List<ToolBoxCategoryAttribute>> activityTuple, int index, TreeNode parentNode, ObservableCollection<TreeNode> currentNodes)
        {
            ActivityNode activityNode = null;
            var categoryCount = activityTuple.Item2.Count;
            if (categoryCount > index)
            {
                var categoryInfo = activityTuple.Item2[index];
                var displayName = categoryInfo.DisplayName;

                var categoryNode = currentNodes.FirstOrDefault(item => !item.IsLeaf && item.DisplayName == displayName);
                if (categoryNode == null)
                {
                    categoryNode = new CategoryNode(categoryInfo);
                    categoryNode.Parent = parentNode;
                    currentNodes.Add(categoryNode);
                }

                if (categoryCount == index + 1)
                {
                    activityNode = _activityNodeCache.FirstOrDefault(item => item.ActivityType == activityTuple.Item1);
                    if (activityNode == null)
                    {
                        activityNode = new ActivityNode(activityTuple.Item1);
                        activityNode.Parent = categoryNode;
                    }
                    categoryNode.Children.Add(activityNode);
                }
                else
                {
                    activityNode = buildNodesRecursion(activityTuple, ++index, categoryNode, categoryNode.Children);
                }
            }

            return activityNode;
        }
        /// <summary>
        /// 收藏树创建
        /// </summary>
        /// <param name="favoriteCategory"></param>
        private void buildFavoriteNodes(FavoriteCategory favoriteCategory)
        {
            var records = RecordRepository.GetFavoriteActivities();

            var pairs = from node in _activityNodeCache
                        join redord in records on node.GetActivityTypeId() equals redord.TypeName
                        select new { Node = node, Sort = redord.Sort };

            foreach (var pair in pairs)
            {
                var cloneNode = pair.Node.Clone() as ActivityNode;
                if (cloneNode != null)
                {
                    cloneNode.Parent = favoriteCategory;
                    cloneNode.SortNo = pair.Sort;
                    favoriteCategory.Children.Add(cloneNode);
                }
            }
        }
        /// <summary>
        /// 最近树创建
        /// </summary>
        /// <param name="recentCategory"></param>
        private void buildRecentNodes(RecentCategory recentCategory)
        {
            var records = RecordRepository.GetRecentActivities();

            var pairs = from node in _activityNodeCache
                        join redord in records on node.GetActivityTypeId() equals redord.TypeName
                        select new { Node = node, Sort = redord.Sort };

            foreach (var pair in pairs)
            {
                var cloneNode = pair.Node.Clone() as ActivityNode;
                if (cloneNode != null)
                {
                    cloneNode.Parent = recentCategory;
                    cloneNode.SortNo = pair.Sort;
                    recentCategory.Children.Add(cloneNode);
                }
            }
        }
        /// <summary>
        /// 在活动树上右键
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void TreeViewItem_PreviewMouseRightButtonDown(object sender, MouseButtonEventArgs e)
        {
            var tvItem = VisualUpwardSearch<TreeViewItem>(e.OriginalSource as DependencyObject) as TreeViewItem;
            if (tvItem != null)
            {
                if (tvItem.ContextMenu != null)
                {
                    var menuItemAdd = LogicalTreeHelper.FindLogicalNode(tvItem.ContextMenu, "itemAddFavorite") as MenuItem;
                    var menuItemRemove = LogicalTreeHelper.FindLogicalNode(tvItem.ContextMenu, "itemRemoveFavorite") as MenuItem;
                    if (menuItemAdd != null && menuItemRemove != null)
                    {
                        menuItemAdd.Header = LocalizationProvider.GetLocalizedString("UCtrlActivitiesToolBox_ContextMenu_MenuItem_AddFavorite");
                        menuItemAdd.Icon = new System.Windows.Controls.Image
                        {
                            Source = new BitmapImage(new Uri("/DWF.Studio;component/Resources/SnippetAndActivity/AddFavorite.png", UriKind.Relative))
                        };
                        menuItemRemove.Header = LocalizationProvider.GetLocalizedString("UCtrlActivitiesToolBox_ContextMenu_MenuItem_RemoveFavorite");
                        menuItemRemove.Icon = new System.Windows.Controls.Image
                        {
                            Source = new BitmapImage(new Uri("/DWF.Studio;component/Resources/SnippetAndActivity/RemoveFavorite.png", UriKind.Relative))
                        };
                        TreeNode node = tvItem.DataContext as TreeNode;
                        if (node != null)
                        {
                            if (node.Parent is FavoriteCategory)
                            {
                                if (menuItemAdd != null)
                                {
                                    menuItemAdd.IsEnabled = false;
                                    menuItemRemove.IsEnabled = true;
                                }
                            }
                            else
                            {

                                var activityNode = node as ActivityNode;
                                if (activityNode != null)
                                {
                                    var isEnabled = _favoriteCategory.Children.Select(item => item as ActivityNode).Any(item => item.ActivityType == activityNode.ActivityType);
                                    menuItemAdd.IsEnabled = !isEnabled;
                                    menuItemRemove.IsEnabled = isEnabled;
                                }
                            }
                        }
                    }
                }

                tvItem.Focus();
                e.Handled = true;
            }
        }
        /// <summary>
        /// 添加收藏
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void MenuItem_AddFavorite(object sender, RoutedEventArgs e)
        {
            var menuItem = VisualUpwardSearch<MenuItem>(e.OriginalSource as DependencyObject) as MenuItem;
            if (menuItem != null)
            {
                var activityNode = menuItem.DataContext as ActivityNode;
                if (activityNode != null)
                {
                    var cloneNode = activityNode.Clone() as ActivityNode;
                    if (cloneNode != null)
                    {
                        cloneNode.Parent = _favoriteCategory;
                        var count = _favoriteCategory.Children.Count;
                        _favoriteCategory.Children.Insert(0, cloneNode);
                        if (count > _favoriteMaxCount)
                        {
                            _favoriteCategory.Children.RemoveAt(count - 1);
                        }
                    }
                    saveFavorite();
                }
            }
        }
        /// <summary>
        /// 删除收藏
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void MenuItem_RemoveFavorite(object sender, RoutedEventArgs e)
        {
            var menuItem = VisualUpwardSearch<MenuItem>(e.OriginalSource as DependencyObject) as MenuItem;
            if (menuItem != null)
            {
                var activityNode = menuItem.DataContext as ActivityNode;
                if (activityNode != null)
                {
                    var removeNode = _favoriteCategory.Children.Select(item => item as ActivityNode).FirstOrDefault(item => item.ActivityType == activityNode.ActivityType);
                    if (removeNode != null)
                    {
                        _favoriteCategory.Children.Remove(removeNode);
                        saveFavorite();
                    }
                }
            }
        }
        /// <summary>
        /// 鼠标移动点击事件监视
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void TvItem_MouseMove(object sender, MouseEventArgs e)
        {
            if (e.LeftButton == MouseButtonState.Pressed)
            {
                var activityNode = tvActivities.SelectedItem as ActivityNode;
                if (activityNode != null)
                {
                    _dragDropActivity = activityNode;

                    IDataObject dataObject = new DataObject();
                    dataObject.SetData(DragDropHelper.WorkflowItemTypeNameFormat, activityNode.ActivityType.AssemblyQualifiedName);
                    try 
                    {
                        DragDrop.DoDragDrop(this, dataObject, DragDropEffects.Copy | DragDropEffects.Link);
                    }
                    catch
                    {
                    }
                }
            }
        }
        /// <summary>
        /// 搜索框查询
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void SearchBox_OnSearch(object sender, SearchEventArgs e)
        {
            var txt = e.SearchText;
            if (!String.IsNullOrWhiteSpace(txt))
            {
                searchNodesRecursion(txt, _nodeCollection);
            }
            else
            {
                searchNodesRecursion(String.Empty, _nodeCollection);
            }
        }
        /// <summary>
        /// 搜索树创建
        /// </summary>
        /// <param name="txt"></param>
        /// <param name="currentNodes"></param>
        private void searchNodesRecursion(string txt, ObservableCollection<TreeNode> currentNodes)
        {
            foreach (var node in currentNodes)
            {
                if (node.IsLeaf)
                {
                    node.Visible = node.DisplayName.ToLower().Contains(txt.ToLower());
                }
                else
                {
                    searchNodesRecursion(txt, node.Children);
                    node.Visible = node.Children.Any(item => item.Visible);
                }
                if (!string.IsNullOrWhiteSpace(txt))
                {
                    node.IsExpanded = true;
                }
                else
                {
                    node.IsExpanded = false;
                }
            }
        }
        /// <summary>
        /// 活动变更事件
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        public void DesignerModelChanged(object sender, System.Activities.Presentation.Services.ModelChangedEventArgs e)
        {
            if (e.ModelChangeInfo != null && e.ModelChangeInfo.Value != null && e.ModelChangeInfo.OldValue == null && e.ModelChangeInfo.ModelChangeType != System.Activities.Presentation.Services.ModelChangeType.CollectionItemRemoved)
            {
                var modelItem = e.ModelChangeInfo.Value;
                if (modelItem != null)
                {
                    var currentValue = modelItem.GetCurrentValue();
                    if (currentValue != null && _dragDropActivity != null)
                    {
                        var activityNode = _recentCategory.Children.Select(item => item as ActivityNode).FirstOrDefault(item => item.ActivityType == _dragDropActivity.ActivityType);
                        if (activityNode != null)
                        {
                            _recentCategory.Children.Remove(activityNode);
                            _recentCategory.Children.Insert(0, activityNode);
                            saveRecent();
                        }
                        else
                        {
                            activityNode = _activityNodeCache.FirstOrDefault(item => item.ActivityType == _dragDropActivity.ActivityType);
                            if (activityNode != null)
                            {
                                var cloneNode = activityNode.Clone() as ActivityNode;
                                if (cloneNode != null)
                                {
                                    cloneNode.Parent = _recentCategory;
                                    var count = _recentCategory.Children.Count;
                                    _recentCategory.Children.Insert(0, cloneNode);
                                    if (count > _recentMaxCount)
                                    {
                                        _recentCategory.Children.RemoveAt(count - 1);
                                    }
                                }
                                saveRecent();
                            }
                        }

                        _dragDropActivity = null;
                    }
                }
            }
        }
        /// <summary>
        /// 保存最近
        /// </summary>
        private void saveRecent()
        {
            List<RecentRecord> recordes = new List<RecentRecord>();
            for (int index = 0; index < _recentCategory.Children.Count; index++)
            {
                var node = _recentCategory.Children[index] as ActivityNode;
                if (node != null)
                {
                    node.SortNo = index;
                    recordes.Add(new RecentRecord() { TypeName = node.GetActivityTypeId(), Sort = index });
                }
            }
            RecordRepository.SaveRecentActivities(recordes);
            _recentCategory.Sort();
        }
        /// <summary>
        /// 保存收藏
        /// </summary>
        private void saveFavorite()
        {
            List<FavoriteRecord> recordes = new List<FavoriteRecord>();
            for (int index = 0; index < _favoriteCategory.Children.Count; index++)
            {
                var node = _favoriteCategory.Children[index] as ActivityNode;
                if (node != null)
                {
                    node.SortNo = index;
                    recordes.Add(new FavoriteRecord() { TypeName = node.GetActivityTypeId(), Sort = index });
                }
            }
            RecordRepository.SaveFavoriteActivities(recordes);
            _favoriteCategory.Sort();
        }
        /// <summary>
        /// 返回约定类型
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="source"></param>
        /// <returns></returns>
        static DependencyObject VisualUpwardSearch<T>(DependencyObject source)
        {
            while (source != null && source.GetType() != typeof(T))
                source = VisualTreeHelper.GetParent(source);

            return source;
        }


        private void btnExpand_Click(object sender, RoutedEventArgs e)
        {
            expandNodesRecursion(_nodeCollection);
        }

        private void btnCollapse_Click(object sender, RoutedEventArgs e)
        {
            collapseNodesRecursion(_nodeCollection);
        }
        /// <summary>
        /// 展开全部节点
        /// </summary>
        /// <param name="currentNodes"></param>
        private void expandNodesRecursion(ObservableCollection<TreeNode> currentNodes)
        {
            foreach (var node in currentNodes)
            {
                if (!node.IsLeaf)
                {
                    node.IsExpanded = true;
                    expandNodesRecursion(node.Children);
                }
            }
        }
        /// <summary>
        /// 收缩全部节点
        /// </summary>
        /// <param name="currentNodes"></param>
        private void collapseNodesRecursion(ObservableCollection<TreeNode> currentNodes)
        {
            foreach (var node in currentNodes)
            {
                if (!node.IsLeaf)
                {
                    node.IsExpanded = false;
                    collapseNodesRecursion(node.Children);
                }
            }
        }
    }
    public class TreeViewItemHelper
    {
        public static bool GetShowBackground(DependencyObject obj)
        {
            return (bool)obj.GetValue(ShowBackgroundProperty);
        }

        public static void SetShowBackground(DependencyObject obj, bool value)
        {
            obj.SetValue(ShowBackgroundProperty, value);
        }
        public static readonly DependencyProperty ShowBackgroundProperty = DependencyProperty.RegisterAttached(
            "ShowBackground",
            typeof(bool),
            typeof(TreeViewItemHelper),
            new PropertyMetadata(OnShowBackground)
        );

        private static void OnShowBackground(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            var item = d as TreeViewItem;
            if (item == null)
                return;
            var node = item.DataContext as ActivityNode;
            if (node == null)
            {
                item.Background = new SolidColorBrush(Colors.Transparent);
                return;
            }
        }
    }
}
